/* 包含头文件-----------------------------------------------------------------*/
#include "flash.h"
#include <string.h>

/* 私有宏定义-----------------------------------------------------------------*/
#define FLASH_PAGE_SIZE             (1024u) /* FLASH页大小 */
#define FLASH_PROGRAM_SIZE          (4u) /* FLASH单次写入大小 */

/* 使能全局中断 */
#define ENABLE_GIE()                do { \
                                    __asm volatile ("cpsie i"); \
                                    }while(0)
/* 关闭全局中断 */
#define DISABLE_GIE()               do { \
                                    __asm volatile ("cpsid i"); \
                                    }while(0)

/* 私有类型定义---------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/

/* 全局变量-------------------------------------------------------------------*/

/* 私有函数原型---------------------------------------------------------------*/


/**
  * @brief  擦除flash
  * @param  startAddr : 起始地址
  * @param  bytes     : 擦除总字节数量
  * @retval 0:擦除成功  1:擦除失败
  */
uint8_t flash_erase(uint32_t startAddr, uint32_t bytes)
{
    uint8_t pageNum = (bytes % FLASH_PAGE_SIZE == 0) ? (bytes / FLASH_PAGE_SIZE) : (bytes / FLASH_PAGE_SIZE + 1);
    
    DISABLE_GIE();
    FLASH_Unlock();
    while(pageNum--)
    {
        if(FLASH_COMPLETE != FLASH_ErasePage(startAddr))
        {
            FLASH_Lock();
            ENABLE_GIE();

            return 1;
        }
        startAddr += FLASH_PAGE_SIZE;
    }
    FLASH_Lock();
    ENABLE_GIE();

    return 0;
}

/**
  * @brief  读flash
  * @param  startAddr : 起始地址
  * @param  pBuf      : 数据存储区
  * @param  len       : 读取数量byte
  * @retval 0:读取成功
  */
uint8_t flash_read(uint32_t startAddr, void *pBuf, uint32_t len)
{
    DISABLE_GIE();
    memcpy(pBuf, (void *)startAddr, len);
    ENABLE_GIE();
    
    return 0;
}

/**
  * @brief  写flash
  * @param  startAddr : 起始地址
  * @param  pBuf      : 数据缓冲区
  * @param  len       : 写入数量byte
  * @retval 0:写入成功  1:写入失败
  */
uint8_t flash_write(uint32_t startAddr, void *pBuf, uint32_t len)
{
    uint32_t *dataTmp;
    
    dataTmp = (uint32_t *)pBuf; /* 类型转换为4字节类型 */
    /* 将写入数量除以单次写入大小计算写入次数并且不满4字节的写入也计入1次写入 */
    len = (len % FLASH_PROGRAM_SIZE == 0) ? (len / FLASH_PROGRAM_SIZE) : (len / FLASH_PROGRAM_SIZE + 1);

    DISABLE_GIE();
    FLASH_Unlock();
    while(len--)
    {
        if(FLASH_COMPLETE != FLASH_ProgramWord(startAddr, *dataTmp))
        {
            FLASH_Lock();
            ENABLE_GIE();

            return 1;
        }
        startAddr += 4;
        dataTmp++;
    }
    FLASH_Lock();
    ENABLE_GIE();

    return 0;
}
